﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Text.RegularExpressions;
using System.Linq;
using HtmlAgilityPack;
using SocialEbola.Lib.HapHelper;
using Wulong.Phone.Dianping.Constants;
using Wulong.Phone.Dianping.Models;

namespace Wulong.Phone.Dianping.Services
{
    public class MerchantService
    {
        private static readonly string BaseUrl = CommonConstants.MobileHomePage;

        public static IObservable<Merchant> ObservableMerchantItem(
            string cityCode,
            string merchantId)
        {
            const string searchClause = "/shop.aspx?pid={0}&c={1}";
            var url = String.Format(BaseUrl + searchClause, merchantId, cityCode);
            var queryUrl = new Uri(url);//YqlHelper.HtmlQuery(url, "//div[@id='content1']");
            return from request in Observable.Return((HttpWebRequest)WebRequest.Create(queryUrl))
                   from response in Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)()
                   from item in GetMerchantDetail(response.GetResponseStream()).ToObservable()
                   .ObserveOn(Scheduler.ThreadPool)
                   select item;
        }

        private static IEnumerable<Merchant> GetMerchantDetail(Stream stream)
        {
            var html = new HtmlDocument();
            html.Load(stream);
            var nameNode = html.DocumentNode.SelectNodes("//div[@class='shop_m']//h4");
            var contactNodes = html.DocumentNode.SelectNodes("//div[@class='shop_m']/p");
            if(contactNodes == null || contactNodes.Count()!=2) throw new Exception("Layout changed");
            var merchant = new Merchant
                               {
                                   Name = nameNode.FirstOrDefault().Value,
                                   Addr = contactNodes.First().Value.Substring(3),
                                   Tel = contactNodes.Last().Value.Substring(3, contactNodes.Last().Value.Length - 7)
                               };
            var rateNodes = html.DocumentNode.SelectNodes("//div[@class='shop_m']//dd/ul/li");
            foreach (var rateNode in rateNodes)
            {
                merchant.DetailRating += rateNode.Value;
            }
            var promoNode = html.DocumentNode.SelectNodes("//div[@class='mbox']/div/a");
            foreach (var promo in promoNode)
            {
                var firstOrDefault = promo.GetAttributes().FirstOrDefault();
                if (firstOrDefault != null)
                    merchant.PromotionLink = firstOrDefault.Value;
            }
            var recommendNodes = html.DocumentNode.SelectNodes("//div[@class='mbox']/ul/li");
            foreach (var recommendNode in recommendNodes)
            {
                merchant.Desc += recommendNode.Value + " ";
            }
            yield return merchant;
        }

        public static IObservable<Merchant> ObservableSearch(
            string keywords,
            string cityCode,
            string channelId,
            string circleId,
            int page,
            string rank
            )
        {
            const string searchClause = "/search.aspx?skey={0}&srid={1}&scid={2}&c={3}&pg={4}&sorder={5}";
            var url = String.Format(BaseUrl + searchClause, keywords, circleId, channelId, cityCode, page, rank);
            var queryUrl = new Uri(url); //YqlHelper.HtmlQuery(url, "//dl[@class='clearfix']");
            return MerchantsQuery(queryUrl);
        }

        public static IObservable<Merchant> ObservableMerchant(
            string circleId,
            string channelId,
            string cityCode,
            int page,
            string rank
            )
        {
            const string searchClause = "/search.aspx?srid={0}&scid={1}&c={2}&pg={3}&sorder={4}";
            var url = String.Format(BaseUrl + searchClause, circleId, channelId, cityCode, page, rank);
            var queryUrl = new Uri(url);//YqlHelper.HtmlQuery(url, "//dl[@class='clearfix']");
            return MerchantsQuery(queryUrl); 
        }

        private static IObservable<Merchant> MerchantsQuery(Uri queryUrl)
        {
            return from request in Observable.Return((HttpWebRequest)WebRequest.Create(queryUrl))
                   from response in Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)()
                   from item in GetMerchantItem(response.GetResponseStream()).ToObservable()
                   //from item in GetMerchantItem(XmlReader.Create(response.GetResponseStream())).ToObservable()
                   .ObserveOn(Scheduler.ThreadPool)
                   select item;
        }

        private static IEnumerable<Merchant> GetMerchantItem(Stream stream)
        {
            var html = new HtmlDocument();
            html.Load(stream);
            var items = html.DocumentNode.Descendants("dl").Where(x=>x.Attributes["class"].Value == "clearfix");
            foreach (var item in items)
            {
                var merchant = new Merchant();
                var re = new Regex("<dt>.+pid=(\\d+)&c=\\d+\"><img src=\"(\\S+)\"></a></dt> <dd><h4><a.+>(.+)</a>.+<span class=\"(\\S+)\"></span>(.*)</p><ul><li>(.+)</li><li>(.+)</li>");
                var match = re.Match(item.InnerHtml);
                if(!match.Success) throw new Exception("Dianping Website has changed its layout, please send email to author.");
                merchant.Id = match.Groups[1].Value;
                merchant.ImageUrl = match.Groups[2].Value;
                merchant.Name = match.Groups[3].Value;
                merchant.OverallRating = "/Images/" + match.Groups[4].Value + ".png";
                merchant.AvgPrice = match.Groups[5].Value;
                merchant.Circle = match.Groups[6].Value;
                merchant.SubCategory = match.Groups[7].Value;
                yield return merchant;
            }
        }
    }
}
